package com.example.dynamicdatabasedemo.config;


import com.baomidou.mybatisplus.entity.GlobalConfiguration;
import com.baomidou.mybatisplus.enums.DBType;
import com.baomidou.mybatisplus.enums.FieldStrategy;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:
 * @Author: dengping.xu
 * @Data: 2021-07-23
 */
@Slf4j
public abstract class DataSourceConfig {

    protected abstract DbMoudleConfig getDbMoudleConfig();

    protected String getCreateDatabaseSQL(){
        return "SELECT id, masterdatabase, masterserver, masterport, masteruserid, masterpassword FROM tb_database_java";
    }

    protected DataSource getDatabase(long id,String database, String host,String port,String username,String password){
        DbMoudleConfig dbMoudleConfig = new DbMoudleConfig();
        dbMoudleConfig.setId(id)
                .setDatabase(database)
                .setHost(host)
                .setUsername(username)
                .setPort(port)
                .setPassword(password)
                .setProtocol(this.getDbMoudleConfig().getProtocol());
        return DynamicDataSource.createDataSource(dbMoudleConfig);
    }

    protected void setDatabases(DataSource mainDataSource, Map<Object, Object> dataSourceMap) throws SQLException {
        Connection conn = mainDataSource.getConnection();
        Throwable var4 = null;
        try {
            Statement statement = conn.createStatement();
            Throwable var6 = null;
            try {
                ResultSet resultSet = statement.executeQuery(this.getCreateDatabaseSQL());
                Throwable var8 = null;
                try {
                    String database;
                    String key;
                    try {
                        for(; resultSet.next();) {
                            long id = resultSet.getLong("id");
                            database = resultSet.getString("masterdatabase");
                            String host = resultSet.getString("masterserver");
                            String port = resultSet.getString("masterport");
                            String username = resultSet.getString("masteruserid");
                            String password = resultSet.getString("masterpassword");
                            key = String.valueOf(id);
                            DataSource dataSource = this.getDatabase(id, database, host, port, username, password);
                            if (dataSource != null) {
                                dataSourceMap.put(key, dataSource);
                                DynamicDataSourceHolder.addSchema(key, database);
                            }
                        }
                    } catch (Throwable var60) {
                        var8 = var60;
                        throw var60;
                    }
                } finally {
                    if (resultSet != null) {
                        if (var8 != null) {
                            try {
                                resultSet.close();
                            } catch (Throwable var59) {
                                var8.addSuppressed(var59);
                            }
                        } else {
                            resultSet.close();
                        }
                    }

                }
            } catch (Throwable var62) {
                var6 = var62;
                throw var62;
            } finally {
                if (statement != null) {
                    if (var6 != null) {
                        try {
                            statement.close();
                        } catch (Throwable var58) {
                            var6.addSuppressed(var58);
                        }
                    } else {
                        statement.close();
                    }
                }
            }
        } catch (Throwable var64) {
            var4 = var64;
            throw var64;
        } finally {
            if (conn != null) {
                if (var4 != null) {
                    try {
                        conn.close();
                    } catch (Throwable var57) {
                        var4.addSuppressed(var57);
                    }
                } else {
                    conn.close();
                }
            }
        }
    }

    @Bean
    public DynamicDataSource dynamicDataSource(){
        DynamicDataSource dynamicDataSource = DynamicDataSource.getInstance();
        Map<Object, Object> databaseMap = new HashMap<>();
        DbMoudleConfig dbMoudleConfig = getDbMoudleConfig();
        DataSource defaultDataSource = DynamicDataSource.createDataSource(dbMoudleConfig);
        databaseMap.put("default",defaultDataSource);
        DynamicDataSourceHolder.addSchema("default", dbMoudleConfig.getDatabase());

        try {
            setDatabases(defaultDataSource,databaseMap);
        } catch (SQLException throwables) {
            log.error("The database init failed");
        }
        dynamicDataSource.setTargetDataSources(databaseMap);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception{
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(dynamicDataSource);
        factoryBean.setMapperLocations((new PathMatchingResourcePatternResolver()).getResources("classpath*:*/mappers/*.xml"));
        GlobalConfiguration globalConfig = new GlobalConfiguration();
        globalConfig.setFieldStrategy(FieldStrategy.NOT_NULL.getKey());
        globalConfig.setIdType(IdType.AUTO.getKey());
        globalConfig.setSqlInjector(new AutoSqlInjector());
        globalConfig.setDbType(DBType.MYSQL.getDb());
        factoryBean.setGlobalConfig(globalConfig);
        factoryBean.setPlugins((new Interceptor[]{new PaginationInterceptor()}));
        return factoryBean.getObject();
    }
}
